package com;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class SocketHelper {
	private static void read(InputStream input, byte[] buff, int offset,
			int length) throws IOException {
		int size = 0;
		int k = 0;
		while (k != -1 && size < length) {
			k = input.read(buff, offset + size, length - size);
			if (k > 0)
				size += k;
		}
	}

	public static String readStr(final InputStream input, int timeout)
			throws IOException, SocketTimeoutEx {
		final String[] ress = new String[1];
		final IOException[] IO = new IOException[1];
		final boolean[] isnull = new boolean[1];
		isnull[0] = false;
		new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					byte[] bytelength = new byte[4];
					read(input, bytelength, 0, 4);
					int reslength = Common.byteArrayToInt(bytelength, 0);
					if (reslength == 0) {
						isnull[0] = true;
						return;
					}
					byte[] bytedata = new byte[reslength];
					read(input, bytedata, 0, reslength);
					ress[0] = new String(bytedata, "utf-8");
				} catch (IOException e) {
					IO[0] = e;
				}

			}
		}).start();
		for (int i = 0; i * 100 < timeout || timeout == 0; i++) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if (ress[0] != null) {
				return ress[0];
			}
			if (isnull[0]) {
				return null;
			}
			if (IO[0] != null) {
				throw IO[0];
			}
		}
		try {
			input.close();
		} catch (Exception e) {
		}
		throw new SocketTimeoutEx();
	}

	public static int readInt(final InputStream input, int timeout)
			throws IOException, SocketTimeoutEx {

		final int[] ress = new int[1];
		ress[0] = Integer.MIN_VALUE;
		final IOException[] IO = new IOException[1];

		new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					byte[] bytelength = new byte[4];
					read(input, bytelength, 0, 4);
					ress[0] = Common.byteArrayToInt(bytelength, 0);
				} catch (IOException e) {
					IO[0] = e;
				}

			}
		}).start();

		for (int i = 0; i * 100 < timeout || timeout == 0; i++) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if (ress[0] != Integer.MIN_VALUE) {
				return ress[0];
			}
			if (IO[0] != null) {
				throw IO[0];
			}
		}
		try {
			input.close();
		} catch (Exception e) {
		}
		throw new SocketTimeoutEx();
	}

	public static int readByte(final InputStream input, int timeout)
			throws IOException, SocketTimeoutEx {
		final int[] ress = new int[1];
		ress[0] = Integer.MIN_VALUE;
		final IOException[] IO = new IOException[1];

		new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					byte[] bytelength = new byte[1];
					read(input, bytelength, 0, 1);
					ress[0] = bytelength[0];
				} catch (IOException e) {
					IO[0] = e;
				}

			}
		}).start();

		for (int i = 0; i * 100 < timeout || timeout == 0; i++) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if (ress[0] != Integer.MIN_VALUE) {
				return ress[0];
			}
			if (IO[0] != null) {
				throw IO[0];
			}
		}
		try {
			input.close();
		} catch (Exception e) {
		}
		throw new SocketTimeoutEx();
	}

	public static byte[] readBytes(final InputStream input, int timeout)
			throws IOException, SocketTimeoutEx {
		final byte[][] ress = new byte[1][];
		final IOException[] IO = new IOException[1];
		final boolean[] isnull = new boolean[1];
		isnull[0] = false;
		new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					byte[] bytelength = new byte[4];
					read(input, bytelength, 0, 4);
					int reslength = Common.byteArrayToInt(bytelength, 0);
					if (reslength == 0) {
						isnull[0] = true;
						return;
					}
					byte[] bytedata = new byte[reslength];
					read(input, bytedata, 0, reslength);
					ress[0] = bytedata;
				} catch (IOException e) {
					IO[0] = e;
				}

			}
		}).start();
		for (int i = 0; i * 100 < timeout || timeout == 0; i++) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if (ress[0] != null) {
				return ress[0];
			}
			if (isnull[0]) {
				return null;
			}
			if (IO[0] != null) {
				throw IO[0];
			}
		}
		try {
			input.close();
		} catch (Exception e) {
		}
		throw new SocketTimeoutEx();
	}

	public static void writeInt(OutputStream output, int str)
			throws IOException {
		byte[] bytelength = Common.intToByteArray(str);
		output.write(bytelength);
		output.flush();
	}

	public static void writeByte(OutputStream output, byte str)
			throws IOException {
		byte[] bytelength = new byte[] { str };
		output.write(bytelength);
		output.flush();
	}

	public static void writeStr(OutputStream output, String str)
			throws IOException {
		if (str != null && !str.equals("")) {
			byte[] data = str.getBytes("utf-8");
			byte[] bytelength = Common.intToByteArray(data.length);
			output.write(bytelength);
			output.write(data);
		} else {
			output.write(Common.intToByteArray(0));
		}
		output.flush();
	}

	public static void writeBytes(OutputStream output, byte[] data)
			throws IOException {
		byte[] bytelength = Common.intToByteArray(data.length);
		output.write(bytelength);
		output.write(data);
		output.flush();
	}
}
